/*
 * Licensed Materials - Property of tenxcloud.com
 * (C) Copyright 2023 TenxCloud. All Rights Reserved.
 * 2023-02-09  @author xyinting
 */

package users

import (
	"cloud_android_backend/pkg/middleware/password"
	model "cloud_android_backend/pkg/models/users"
	"cloud_android_backend/pkg/utils"
	"context"
	"errors"
	"fmt"
	"math/rand"

	"github.com/golang/glog"
	"github.com/redis/go-redis/v9"
	"modules.tenxcloud.com/common/composite"
)

func CheckVerifyCode(body *model.UserPwdReset) (*model.UserPwdResetResponse, error) {

	db, err := composite.Database.GetOrm()
	if err != nil {
		glog.Error(err)
		return nil, err
	}

	user := model.New()
	if err := user.GetByUsername(db, body.UserName); err != nil {
		glog.Errorf("get user info failed, userName %s, error %v", body.UserName, err)
		return nil, err
	}

	if user.Phone != body.Phone {
		glog.Warningf("user and phone not match")
		return nil, errors.New("user and phone not match")
	}

	redisCli := utils.GetRedis()
	_, err = redisCli.Get(context.Background(), utils.SMSCodeKey(body.Phone)).Result()
	if err != nil {
		if err == redis.Nil {
			glog.Warningf("key not found, key %s", utils.SMSCodeKey(body.Phone))
			return nil, errors.New("code expired")
		}
		glog.Errorf("get verify code failed, key %s, errors %v", utils.SMSCodeKey(body.Phone), err)
		return nil, err
	}

	// todo verify phone code
	//if result != body.Code {
	//	glog.Warningf("code not match, get %s but %s", result, body.Code)
	//	return nil, errors.New("code incorrect")
	//}

	token := GenerateToken()
	if err := redisCli.Set(context.Background(), utils.UserPwdResetKey(user.UserName), token, utils.EXPIRE_TIME_USER_PWD_RESET).Err(); err != nil {
		glog.Errorf("set key to redis failed, error %v", err)
		return nil, err
	}

	return &model.UserPwdResetResponse{
		UserName: user.UserName,
		Phone:    user.Phone,
		Code:     token,
	}, nil

}

func ResetPwd(body *model.UserPwdReset) error {

	if body.Code == "" {
		glog.Warningf("code not empty")
		return errors.New("code not empty")
	}

	if body.Password != body.ConformPassword {
		glog.Warningf("password not match")
		return errors.New("password not match")
	}

	redisCli := utils.GetRedis()
	result, err := redisCli.Get(context.Background(), utils.UserPwdResetKey(body.UserName)).Result()
	if err != nil {
		if err == redis.Nil {
			glog.Warningf("key not found, key %s", utils.UserPwdResetKey(body.UserName))
			return errors.New("cod expired")
		}
		glog.Errorf("get verify code failed, key %s, errors %v", utils.SMSCodeKey(body.Phone), err)
		return err
	}

	if result != body.Code {
		glog.Warningf("code not match, get %s but %s", result, body.Code)
		return errors.New("code incorrect")
	}

	db, err := composite.Database.GetOrm()
	if err != nil {
		glog.Error(err)
		return err
	}

	user := model.New()
	if err := user.GetByUsername(db, body.UserName); err != nil {
		glog.Error("get user failed, error %e", err)
		return err
	}

	if p, err := password.Encrypt(body.Password); err != nil {
		glog.Errorf("encode user password failed, error %v", err)
		return err
	} else {
		user.Password = p
	}

	if err := user.UpdateByConditions(db, map[string]interface{}{"password": user.Password}); err != nil {
		glog.Errorf("update user password failed, user %s, error %v", user.UserName, err)
		return err
	}

	return nil
}

func GenerateToken() string {
	randBytes := make([]byte, 8)
	rand.Read(randBytes)
	return fmt.Sprintf("%x", randBytes)
}
